#ifndef ranges_HPP__
#define ranges_HPP__

#include "categories.hpp"
#include "range_traits.hpp"

//--------------------------------------------------------

template <typename T>
struct input_range 
{
	//TODO: usar traits
	typedef T value_type;
	typedef input_range_tag range_category;

	input_range( T* begin, T* end )
		: begin_(begin), end_(end)
	{}

	bool empty() const
	{
		return begin_ == end_;
	}

	void popFront()
	{
		++begin_;
	}

	T& front() const
	{
		return *begin_;
	}

	T* begin_;
	T* end_;
};

//--------------------------------------------------------

template <typename T> 
struct bidir_range 
{
	typedef T value_type;
	typedef bidirectional_range_tag range_category;

	bidir_range( T* begin, T* end )
		: begin_(begin), end_(end)
	{}

	bool empty() const
	{
		return begin_ == end_;
	}

	void popFront()
	{
		++begin_;
	}

	void popBack()
	{
		--end_;			//???
	}

	T& front() const
	{
		return *begin_;
	}

	T& back() const
	{
		return *end_;	//???
	}

	T* begin_;
	T* end_;
};

//--------------------------------------------------------

template <typename T> 
struct random_access_range 
{
	typedef T value_type;
	typedef random_access_range_tag range_category;

	random_access_range( T* begin, T* end )
		: begin_(begin), end_(end)
	{}

	bool empty() const
	{
		return begin_ == end_;
	}

	void popFront()
	{
		++begin_;
	}

	void popBack()
	{
		--end_;			//???
	}

	T& front() const
	{
		return *begin_;
	}

	T& back() const
	{
		return *end_;	//???
	}

	//TODO: others members

	T* begin_;
	T* end_;
};


//--------------------------------------------------------

template <typename Range> 
struct Retro
{
	typedef typename Range::value_type value_type;
	//TODO: puede ser random access
	typedef typename Range::value_type range_category;

//	Retro( Range const& range )
//		: range_( range.end_-1, range.begin_-1 )
//	{
//
////		auto xxx = (range.end_)-1;
////		//auto yyy = range.begin_--;
////
////		xxx+1;
//
//	}

	Retro( Range const& range )
		: range_( range.begin_-1, range.end_-1 )
	{
	}

	bool empty() const 
	{ 
		return range_.empty(); 
	}

	void popFront() 
	{ 
		return range_.popBack(); 
	}

	void popBack() 
	{
		return range_.popFront(); 
	}

	//TODO: replace with Template Alias
	//E<Range>::Type& front() const
	typename range_value_type<Range>::type& front() const
	{ 
		return range_.back();
	}

	//E<Range>::Type& back() const
	typename range_value_type<Range>::type& back() const
	{ 
		return range_.front(); 
	}

	Range range_;
};

template <typename Range> 
Retro<Range> retro(Range r) 
{
	return Retro<Range>(r);
}
template <typename Range> 
Range retro(Retro<Range> r) 
{
	return r.range_; // klever
}


//--------------------------------------------------------

#endif // ranges_HPP__
